package cn.ppool.xmlmapper.utils;

import lombok.extern.log4j.Log4j2;
import org.springframework.beans.factory.FactoryBean;
import org.springframework.beans.factory.config.ConfigurableListableBeanFactory;
import org.springframework.beans.factory.support.*;
import org.springframework.context.ApplicationContext;
import org.springframework.context.ConfigurableApplicationContext;

import java.util.ArrayList;
import java.util.List;
import java.util.Map;

@Log4j2
public class BeanUtil {


    public static <T> T getBean(ApplicationContext context, Class<T> clazz) {
        return context.getBean(clazz);
    }

    public static <C> void registerBean(ApplicationContext context, Class<C> clazz, String beanName, Map<String, Object> propertyValues) {
        ConfigurableApplicationContext configurableApplicationContext = (ConfigurableApplicationContext) context;
        ConfigurableListableBeanFactory configurableListableBeanFactory = configurableApplicationContext.getBeanFactory();
        GenericBeanDefinition readyInitBean = new GenericBeanDefinition();
        readyInitBean.setBeanClass(clazz);
        readyInitBean.getPropertyValues().addPropertyValues(propertyValues);
        ((DefaultListableBeanFactory) configurableListableBeanFactory).registerBeanDefinition(beanName, readyInitBean);
    }


    public static <C, F extends FactoryBean<C>> void registerProxyBean(ApplicationContext context, Class<F> proxyClass, Class<C> clazz, String beanName, Map<String, Object> propertyValues) {
        BeanDefinitionBuilder builder = BeanDefinitionBuilder.genericBeanDefinition(clazz);     // 选择要代理的接口
        GenericBeanDefinition definition = (GenericBeanDefinition) builder.getRawBeanDefinition();
        GenericBeanDefinition bd = new GenericBeanDefinition();
        bd.setBeanClass(proxyClass);
        propertyValues.put("interfaceClass", definition.getBeanClassName());
        registerBean(context, proxyClass, beanName, propertyValues);
    }


    public static <C> void registerBean(BeanDefinitionRegistry registry, Class<C> clazz, String beanName, Map<String, Object> propertyValues) {
        registerBean(registry, clazz, beanName, propertyValues, new ArrayList<>());
    }

    public static <C> void registerBean(BeanDefinitionRegistry registry, Class<C> clazz, String beanName, Map<String, Object> propertyValues, List<Object> constructorArg) {
        BeanDefinitionBuilder definition = BeanDefinitionBuilder.genericBeanDefinition(clazz);
        definition.setAutowireMode(AbstractBeanDefinition.AUTOWIRE_BY_TYPE);
        definition.setLazyInit(false);
        for (Object constructor : constructorArg) {
            definition.addConstructorArgValue(constructor);
        }
        for (Map.Entry<String, Object> mval : propertyValues.entrySet()) {
            definition.addPropertyValue(mval.getKey(), mval.getValue());
        }
        registry.registerBeanDefinition(beanName, definition.getBeanDefinition());
    }


    public static <C, F extends FactoryBean<C>> void registerProxyBean(BeanDefinitionRegistry registry, Class<F> proxyClass, Class<C> clazz, String beanName, Map<String, Object> propertyValues) {
        registerProxyBean(registry, proxyClass, clazz, beanName, propertyValues, new ArrayList<>());
    }

    public static <C, F extends FactoryBean<C>> void registerProxyBean(BeanDefinitionRegistry registry, Class<F> proxyClass, Class<C> clazz, String beanName, Map<String, Object> propertyValues, List<Object> constructorArg) {
        BeanDefinitionBuilder builder = BeanDefinitionBuilder.genericBeanDefinition(clazz);     // 选择要代理的接口
        GenericBeanDefinition definition = (GenericBeanDefinition) builder.getRawBeanDefinition();
        GenericBeanDefinition bd = new GenericBeanDefinition();
        bd.setBeanClass(proxyClass);
        propertyValues.put("interfaceClass", definition.getBeanClassName());
        registerBean(registry, proxyClass, beanName, propertyValues, constructorArg);
    }

}
